package com.hhd.flow.engine.cmd.impl;

import com.alibaba.fastjson.JSONObject;
import com.hhd.flow.engine.utils.CommonUtils;
import com.hhd.flow.engine.vo.ApproveType;
import com.hhd.flow.engine.vo.FlowNode;
import com.hhd.flow.engine.vo.UserManualSelect;
import com.hhd.flow.engine.vo.UserTask;
import com.hhd.flow.entity.FlowProcessInstance;
import com.hhd.flow.entity.FlowTask;
import com.hhd.flow.entity.FlowUserTask;
import com.hhd.flow.entity.FlowUserTaskHistory;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Setter
@Getter
@SuperBuilder(toBuilder = true)
public class AutoCompleteCommand<T> extends BaseCommand<T> {
    private FlowProcessInstance flowProcessInstance;
    private List<FlowUserTaskHistory> taskHistories;
    private Set<String> approvedUserIds;
    private JSONObject formModel;
    private UserManualSelect userManualSelect;

    protected void autoComplete(FlowProcessInstance flowProcessInstance,
                                JSONObject formModel,
                                UserManualSelect userManualSelect) {
        this.flowProcessInstance = flowProcessInstance;
        this.formModel = formModel;
        this.userManualSelect = userManualSelect;
        while (true) {
            this.loadFlowUserTaskHistory();
            List<FlowTask> flowTasks = getEngine().getFlowTaskService().lambdaQuery()
                    .eq(FlowTask::getProcessInstanceId, flowProcessInstance.getId())
                    .eq(FlowTask::getType, FlowNode.FlowNodeType.userTask.name())
                    .list();
            if (CommonUtils.isEmpty(flowTasks)) return;
            boolean flag = false;
            for (FlowTask flowTask : flowTasks) {
                List<FlowUserTask> flowUserTasks = getFlowUserTasks(flowTask);
                if (CommonUtils.isEmpty(flowUserTasks)) continue;
                if (canAutoPass(flowUserTasks, flowTask)) {
                    FlowUserTask flowUserTask = getPassAbleTask(flowUserTasks, flowTask);

                    if(CommonUtils.isEmpty(flowUserTask)) continue;
                    this.autoComplete(flowUserTask);
                    flag = true;
                    break;
                }
            }
            if (!flag) break;
            List<FlowUserTask> list = getEngine().getFlowUserTaskService()
                    .lambdaQuery()
                    .eq(FlowUserTask::getProcessInstanceId, flowProcessInstance.getId())
                    .eq(FlowUserTask::getSupportAutoComplete, true)
                    .eq(FlowUserTask::getNotify, false)
                    .list();

            if (CommonUtils.isEmpty(list)) break;
            this.autoComplete(list.get(0));
        }
    }

    private FlowUserTask getPassAbleTask(List<FlowUserTask> flowUserTasks, FlowTask flowTask) {
        for (FlowUserTask flowUserTask : flowUserTasks) {
            if (approvedUserIds.contains(flowUserTask.getUserId())) {
                return flowUserTask;
            }
        }
        return null;
    }

    private boolean canAutoPass(List<FlowUserTask> flowUserTasks, FlowTask flowTask) {
        UserTask.ExecuteWay executeWay = UserTask.ExecuteWay.valueOf(flowTask.getExecuteWay());
        if (!flowUserTasks.get(0).getSupportAutoComplete()) return false;

        if (executeWay == UserTask.ExecuteWay.single) {
            if (flowUserTasks.size() <= 1) return true;
            return false;
        }

        if (executeWay == UserTask.ExecuteWay.multiCompetition) {
            if (flowUserTasks.size() <= 1) return true;
            return false;
        }

        if (executeWay == UserTask.ExecuteWay.multiSequence) {
            return true;
        }

        if (executeWay == UserTask.ExecuteWay.multiSequence) {
            return true;
        }
        return false;
    }

    private List<FlowUserTask> getFlowUserTasks(FlowTask flowTask) {
        return getEngine().getFlowUserTaskService().lambdaQuery()
                .eq(FlowUserTask::getTaskInstanceId, flowTask.getId())
                .list();
    }

    private void loadFlowUserTaskHistory() {
        taskHistories = getEngine().getFlowUserTaskHistoryService().lambdaQuery()
                .eq(FlowUserTaskHistory::getProcessInstanceId, flowProcessInstance.getId())
                .eq(FlowUserTaskHistory::getNotify, false)
                .list();
        approvedUserIds = taskHistories.stream().map(FlowUserTaskHistory::getUserId).collect(Collectors.toSet());
        approvedUserIds.add(flowProcessInstance.getApplyBy());
    }

    private void autoComplete(FlowUserTask flowUserTask) {
        CompleteUserTaskCommand command = getEngine().newCompleteUserTaskCommandBuilder()
                .flowUserTaskId(flowUserTask.getId())
                .userManualSelect(userManualSelect)
                .formModel(formModel)
                .comment("自动审批完成")
                .userSign(null)
                .attachmentIds(null)
                .approveType(ApproveType.approve)
                .commentInfo(null).build();
        getEngine().execute(command);
    }
}
